package cn.kgc.util.resultutil.advice;

import cn.hutool.json.JSONUtil;
import cn.kgc.util.resultutil.IgnoreResult;
import cn.kgc.util.resultutil.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author YC
 * 自定义AOP
 * 判断控制器是否添加@IgnoreResult 没有则封装到Result对象 有则不封装
 * ControllerAdvice("cn.kgc.controller")注解 表示给对应控制器添加增强（封装结果）
 */
@ControllerAdvice("cn.kgc.controller")
public class ResultAdvice implements ResponseBodyAdvice<Object> {

    /**
     * 判断是否需要拦截（是否执行beforeBodyWrite方法）
     *
     * @param returnType    控制器方法的返回值类型
     * @param converterType 消息转换器
     * @return true表示拦截 false表示不拦截
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 如果类上没有自定义@IgnoreResult注解，则进行结果封装
        return !returnType.getExecutable().isAnnotationPresent(IgnoreResult.class);
    }

    /**
     * 控制器返回结果之前执行的方法
     * 在返回结果之前获取结果，通过这个方法封装到自定义类Result对象中再返回
     *
     * @param body                  控制器中原来方法的返回值
     * @param returnType            返回值类型
     * @param selectedContentType   返回值类型
     * @param selectedConverterType 返回值类型
     * @param request               请求域
     * @param response              响应域
     * @return 封装后的数据
     */
    @Override
    public Object beforeBodyWrite(
            Object body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType,
            ServerHttpRequest request, ServerHttpResponse response
    ) {
        if (body == null) {
            //如果控制器中原来的返回结果是null 直接返回一个包含null的Result对象
            return Result.success();
        } else if (body instanceof Result) {
            //如果控制器的方法中原来的返回结果是result对象 直接将result对象返回
            return body;
        } else if (body instanceof String) {
            //如果控制器的方法中原来的返回结果是String类型，则将String类型封装到Result对象中返回
            return JSONUtil.toJsonStr(Result.success(body));
        } else {
            //如果控制器的方法中原来的返回结果直接封装Result对象
            return Result.success(body);
        }
    }
}